package com.zyzg.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException;
import com.zyzg.constant.Constants;
import com.zyzg.domain.GpsData;
import com.zyzg.domain.GpsDistrict;
import com.zyzg.domain.GpsReal;
import com.zyzg.domain.Position;
import com.zyzg.factory.ExecutorFactory;
import com.zyzg.listenter.BusinessMsgListener;
import com.zyzg.mapper.DataMapper;
import com.zyzg.service.GpsDataService;
import com.zyzg.service.IDataService;
import com.zyzg.utils.CoordinateTransformUtil;
import com.zyzg.utils.CoordinateValidator;
import com.zyzg.utils.DateUtils;
import com.zyzg.utils.TDTGPSUtils;
import com.zyzg.utils.redis.RedisCache;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.*;

/**
 * @Author: lurui
 * @CreateTime: 2021-03-29 11:25
 * @Description: ${Description}
 */
@Slf4j
@Service
public class DataServiceImpl implements IDataService {

    @Autowired
    private DataMapper dataMapper;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private GpsDataService gpsDataService;

    @Autowired
    private BusinessMsgListener businessMsgListener;

    @PostConstruct
    public void init(){
        // 启动时，从数据库中加载车辆配置信息，并缓存到Redis中
        refreshCarConfig();

        // 启动时，从数据库中加载车辆实时GPS数据，并缓存到Redis中
        refreshRealGpsData();

        // 处理缓存队列中的数据
        handleCacheQueue();

    }

    private void handleCacheQueue() {
        ExecutorService executor = ExecutorFactory.getInstance();

        // 提交实时GPS数据处理任务到线程池
        executor.submit(() -> {
            while (true) {
                try {
                    ConcurrentLinkedQueue<JSONObject> queue_0200 = businessMsgListener.getQueue_0200();
                    JSONObject msg;
                    while ((msg = queue_0200.poll()) != null) {
                        try {
                            // 处理消息，这里可以调用你现有的处理方法
                            handleRealMsg(msg);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                    // 短暂休眠，避免CPU空转
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        });

        // 提交实时GPS报警数据处理任务到线程池
//        executor.submit(() -> {
//            while (true) {
//                try {
//                    ConcurrentLinkedQueue<JSONObject> queue_0200 = businessMsgListener.getQueue_0200();
//                    JSONObject msg;
//                    while ((msg = queue_0200.poll()) != null) {
//                        try {
//                            // 处理消息
//                            handleAlarmMsg(msg);
//                        } catch (Exception e) {
//                            e.printStackTrace();
//                        }
//                    }
//                    // 短暂休眠，避免CPU空转
//                    Thread.sleep(100);
//                } catch (InterruptedException e) {
//                    Thread.currentThread().interrupt();
//                    break;
//                }
//            }
//        });

        // 提交实时GPS历史数据处理任务到线程池
        executor.submit(() -> {
            while (true) {
                try {
                    ConcurrentLinkedQueue<JSONObject> queue_0200 = businessMsgListener.getQueue_0200();
                    JSONObject msg;
                    while ((msg = queue_0200.poll()) != null) {
                        try {
                            // 处理消息，这里可以调用你现有的处理方法
                            handleHistoryAndAreaMsg(msg);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                    // 短暂休眠，避免CPU空转
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        });

        // 提交补报GPS数据处理任务到线程池
        executor.submit(() -> {
            while (true) {
                try {
                    ConcurrentLinkedQueue<JSONObject> queue_0200 = businessMsgListener.getQueue_0704();
                    JSONObject msg;
                    while ((msg = queue_0200.poll()) != null) {
                        try {
                            // 处理消息
                            handleRepairRealMsg(msg);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                    // 短暂休眠，避免CPU空转
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        });

        // 提交补报GPS数据处理任务到线程池
//        executor.submit(() -> {
//            while (true) {
//                try {
//                    ConcurrentLinkedQueue<JSONObject> queue_0200 = businessMsgListener.getQueue_0704();
//                    JSONObject msg;
//                    while ((msg = queue_0200.poll()) != null) {
//                        try {
//                            // 处理消息
//                            handleRepairAlarmMsg(msg);
//                        } catch (Exception e) {
//                            e.printStackTrace();
//                        }
//                    }
//                    // 短暂休眠，避免CPU空转
//                    Thread.sleep(100);
//                } catch (InterruptedException e) {
//                    Thread.currentThread().interrupt();
//                    break;
//                }
//            }
//        });

        // 提交补报GPS数据处理任务到线程池
        executor.submit(() -> {
            while (true) {
                try {
                    ConcurrentLinkedQueue<JSONObject> queue_0200 = businessMsgListener.getQueue_0704();
                    JSONObject msg;
                    while ((msg = queue_0200.poll()) != null) {
                        try {
                            // 处理消息，这里可以调用你现有的处理方法
                            handleRepairHistoryAndAreaMsg(msg);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                    // 短暂休眠，避免CPU空转
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        });
    }

    private void refreshRealGpsData() {
        List<GpsReal> carGpsRealList = dataMapper.getRealGpsData();
        for (GpsReal gpsReal : carGpsRealList) {
            if (gpsReal.getGpsTime() != null) {
                JSONObject jsonCache = new JSONObject();
                jsonCache.put("terminalCode", gpsReal.getTerminalCode());
                jsonCache.put("gpsTime", gpsReal.getGpsTime());
                jsonCache.put("lng", gpsReal.getLng());
                jsonCache.put("lat", gpsReal.getLat());
                redisCache.setCacheMapValue("gpsRealList", gpsReal.getConfigId()+"", jsonCache);
            }
        }
    }


    private void refreshCarConfig() {
        redisCache.deleteCacheMap("carConfig");
        List<JSONObject> carConfigList = dataMapper.getCarConfigList();
        for (JSONObject carConfig : carConfigList) {
            redisCache.setCacheMapValue("carConfig", carConfig.getString("device_number"), carConfig);
        }
    }

    @Scheduled(fixedDelay = 60*1000)  // 每1分钟执行一次,将缓存的位置写入数据库
    public void refreshPositionInfo() {
        try {
            Map<String, JSONObject> allPositionInfo = redisCache.getAllDataFromDirectory("position:info");
            for (String cacheKey : allPositionInfo.keySet()) {
                String[] str = cacheKey.split(":");
                String key = str[str.length - 1];
                if(!redisCache.hasKey("cacheKeys:"+key)){
                    dataMapper.savePositionInfo(key, allPositionInfo.get(cacheKey).toJSONString());
                    redisCache.setCacheObject("cacheKeys:"+key, key);
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    @Override
    @Transactional
    public void handleRealMsg(JSONObject json) {
//        log.info("处理实时GPS数据:{}", JSON.toJSONString(json));
        if(json.getDouble("lng")==null){
            return;
        }
        // 验证经纬度合法性， 不合法则不处理
        if (!CoordinateValidator.isValidCoordinates(json.getDouble("lat"), json.getDouble("lng"))) {
            return;
        }
        if ((roundToPrecision(json.getDouble("lng"),4) + "_" + roundToPrecision(json.getDouble("lat"),4)).equals("0.0_0.0")){
            return;
        }

        // 先缓存到本地，每100条批量插入数据库一次
        // 根据消息内容，从缓存中获取车辆配置ID
        String tid = json.getString("tid").substring(1);
        JSONObject cacheJson = redisCache.getCacheMapValue("carConfig", tid);
        if (cacheJson != null) {
            int configId = cacheJson.getIntValue("config_id");
            // GPS实时信息
            GpsReal gpsReal = new GpsReal();
            try {
                gpsReal.setConfigId(configId);
                // 处理GPS实时信息
                gpsReal.setTerminalCode(tid);

                // 处理坐标转换
                handleCoordinateConvert(json, gpsReal);
                gpsReal.setHeight(json.getInteger("height"));
                gpsReal.setSpeed(json.getDouble("speed"));
                gpsReal.setDirection(json.getInteger("direction"));
                gpsReal.setGpsTime(DateUtils.handleGpsTime("yyyyMMddHHmmss", json.getString("gpstime")));
                gpsReal.setCreateTime(new Date());

                // 处理附加信息
                if (json.getDouble("A01") != null) {
                    gpsReal.setMileage(roundToPrecision(json.getDouble("A01") / 10, 1));
                }
                if (json.getDouble("A02") != null) {
                    gpsReal.setOil(roundToPrecision(json.getDouble("A02") / 10, 1));
                }else {
                    gpsReal.setOil(0.0D);
                }

                // 处理报警位
                Integer alarm = json.getInteger("alarm");
                gpsReal.setAbnormalState(alarm);

                // 处理报警描述
                handleAlarmStr(alarm, gpsReal);

                Integer status = json.getInteger("status");
                // 通过位运算处理状态位
                gpsReal.setAccState(status & 0x01);
                gpsReal.setLocation((status >> 1) & 0x01);
                gpsReal.setWeft((status >> 2) & 0x01);
                gpsReal.setWarp((status >> 3) & 0x01);
                gpsReal.setWorkState((status >> 4) & 0x01);


                gpsReal.setLastTime(new Date());

                // 将实时GPS信息放到缓冲队列中，每100条批量插入数据库一次
                Constants.GPS_QUEUE.add(gpsReal);
                if (gpsReal.getGpsTime() != null) {
                    JSONObject jsonCache = new JSONObject();
                    jsonCache.put("terminalCode", gpsReal.getTerminalCode());
                    jsonCache.put("gpsTime", gpsReal.getGpsTime());
                    jsonCache.put("lng", gpsReal.getLng());
                    jsonCache.put("lat", gpsReal.getLat());
                    redisCache.setCacheMapValue("gpsRealList", gpsReal.getConfigId()+"", jsonCache);
                }

//                if (Constants.GPS_QUEUE.size() >= 100) {
//                    List<GpsReal> gpsRealList = new ArrayList<>();
//                    Constants.GPS_QUEUE.drainTo(gpsRealList);
//                    // 批量插入数据库
//                    if (!gpsRealList.isEmpty()) {
//                        // 批量插入数据库
//                        dataMapper.saveRealAll(gpsRealList);
//                    }
//                    gpsRealList.clear();
//                }
                if (Constants.GPS_QUEUE.size() >= 100) {
                    List<GpsReal> gpsRealList = new ArrayList<>();
                    Constants.GPS_QUEUE.drainTo(gpsRealList);
                    // 批量插入数据库
                    if (!gpsRealList.isEmpty()) {
                        int maxRetries = 3; // 最大重试次数
                        int retryCount = 0;
                        boolean success = false;
                        while (retryCount < maxRetries && !success) {
                            try {
                                // 批量插入数据库
                                dataMapper.saveRealAll(gpsRealList);
                                success = true;
                            } catch (Exception e) {
                                if (e instanceof MySQLTransactionRollbackException && e.getMessage().contains("Deadlock found")) {
                                    retryCount++;
                                    try {
                                        // 等待一段时间后重试
                                        Thread.sleep(500);
                                    } catch (InterruptedException ie) {
                                        Thread.currentThread().interrupt();
                                    }
                                } else {
                                    // 其他异常，抛出
                                    throw e;
                                }
                            }
                        }
                        if (!success) {
                            // 达到最大重试次数仍未成功，记录日志或进行其他处理
                            System.err.println("达到最大重试次数仍未成功，记录日志或进行其他处理.");
                        }
                    }
                    gpsRealList.clear();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    // 处理坐标转换
    private static void handleCoordinateConvert(JSONObject json, GpsReal gpsReal) {
        Double lng = json.getDouble("lng");
        Double lat = json.getDouble("lat");
        // 火星转天地图
        CoordinateTransformUtil.Coordinate wgs84ToCgcs2000 = CoordinateTransformUtil.wgs84ToCgcs2000(lng, lat);
        // 火星转高德
        CoordinateTransformUtil.Coordinate wgs84ToGcj02 = CoordinateTransformUtil.wgs84ToGcj02(lng, lat);
        // 火星转百度
        CoordinateTransformUtil.Coordinate wgs84ToBd09 = CoordinateTransformUtil.wgs84ToBd09(lng, lat);
        gpsReal.setLng(BigDecimal.valueOf(wgs84ToCgcs2000.getLongitude()).setScale(6, RoundingMode.HALF_UP));
        gpsReal.setLat(BigDecimal.valueOf(wgs84ToCgcs2000.getLatitude()).setScale(6, RoundingMode.HALF_UP));
        gpsReal.setGdLng(BigDecimal.valueOf(wgs84ToGcj02.getLongitude()).setScale(6, RoundingMode.HALF_UP));
        gpsReal.setGdLat(BigDecimal.valueOf(wgs84ToGcj02.getLatitude()).setScale(6, RoundingMode.HALF_UP));
        gpsReal.setBaiduLng(BigDecimal.valueOf(wgs84ToBd09.getLongitude()).setScale(6, RoundingMode.HALF_UP));
        gpsReal.setBaiduLat(BigDecimal.valueOf(wgs84ToBd09.getLatitude()).setScale(6, RoundingMode.HALF_UP));
    }

    @Override
    @Transactional
    public void handleAlarmMsg(JSONObject json) {
//        log.info("处理实时GPS报警数据:{}", JSON.toJSONString(json));
        if(json.getDouble("lng")==null){
            return;
        }
        if (!CoordinateValidator.isValidCoordinates(json.getDouble("lat"), json.getDouble("lng"))) {
            return;
        }
        if ((roundToPrecision(json.getDouble("lng"),4) + "_" + roundToPrecision(json.getDouble("lat"),4)).equals("0.0_0.0")){
            return;
        }
        // 先缓存到本地，每100条批量插入数据库一次
        // 根据消息内容，从缓存中获取车辆配置ID
        String tid = json.getString("tid").substring(1);
        JSONObject cacheJson = redisCache.getCacheMapValue("carConfig", tid);
        if (cacheJson != null) {
            int configId = cacheJson.getIntValue("config_id");
            // GPS实时信息
            GpsReal gpsReal = new GpsReal();
            try {
                gpsReal.setConfigId(configId);
                gpsReal.setTerminalCode(tid);
                // 处理报警位
                Integer alarm = json.getInteger("alarm");
                gpsReal.setAbnormalState(alarm);

                // 处理报警描述
                handleAlarmStr(alarm, gpsReal);

                Integer status = json.getInteger("status");
                // 通过位运算处理状态位
                gpsReal.setAccState(status & 0x01);
                gpsReal.setLocation((status >> 1) & 0x01);
                gpsReal.setWeft((status >> 2) & 0x01);
                gpsReal.setWarp((status >> 3) & 0x01);
                gpsReal.setWorkState((status >> 4) & 0x01);


                gpsReal.setLastTime(new Date());

                Constants.GPS_STATUS_QUEUE.add(gpsReal);

//                if (Constants.GPS_STATUS_QUEUE.size() >= 100) {
//                    List<GpsReal> gpsRealList = new ArrayList<>();
//                    Constants.GPS_STATUS_QUEUE.drainTo(gpsRealList);
//                    // 批量插入数据库
//                    if (!gpsRealList.isEmpty()) {
//                        // 批量插入数据库
//                        dataMapper.saveRealOtherAll(gpsRealList);
//                    }
//                    gpsRealList.clear();
//                }

                if (Constants.GPS_STATUS_QUEUE.size() >= 133) {
                    List<GpsReal> gpsRealList = new ArrayList<>();
                    Constants.GPS_STATUS_QUEUE.drainTo(gpsRealList);
                    // 批量插入数据库
                    if (!gpsRealList.isEmpty()) {
                        int maxRetries = 3; // 最大重试次数
                        int retryCount = 0;
                        boolean success = false;
                        while (retryCount < maxRetries && !success) {
                            try {
                                // 批量插入数据库
                                dataMapper.saveRealOtherAll(gpsRealList);
                                success = true;
                            } catch (Exception e) {
                                if (e instanceof MySQLTransactionRollbackException && e.getMessage().contains("Deadlock found")) {
                                    retryCount++;
                                    try {
                                        // 等待一段时间后重试
                                        Thread.sleep(500);
                                    } catch (InterruptedException ie) {
                                        Thread.currentThread().interrupt();
                                    }
                                } else {
                                    // 其他异常，抛出
                                    throw e;
                                }
                            }
                        }
                        if (!success) {
                            // 达到最大重试次数仍未成功，记录日志或进行其他处理
                            System.err.println("Failed to insert data after multiple retries due to deadlock.");
                        }
                    }
                    gpsRealList.clear();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    // 处理报警描述
    private static void handleAlarmStr(Integer alarm, GpsReal gpsReal) {
        // 转换为二进制字符串
        String alarmStr = Integer.toBinaryString(alarm);
        String[] alarmDescriptions = {
                "紧急报警", "超速报警", "疲劳驾驶", "危险预警", "GNSS 模块发生故障",
                "GNSS 天线未接或被剪断", "GNSS 天线短路", "终端主电源欠压", "终端主电源掉电",
                "终端 LCD 或显示器故障", "TTS 模块故障", "摄像头故障", "道路运输证 IC 卡模块故障",
                "超速预警", "疲劳驾驶预警", null, null, null, "当天累计驾驶超时", "超时停车",
                "进出区域", "进出路线", "路段行驶时间不足/过长", "路线偏离报警", "车辆 VSS 故障",
                "车辆油量异常", "车辆被盗(通过车辆防盗器)", "车辆非法点火", "车辆非法位移",
                "碰撞预警", "侧翻预警", "非法开门报警"
        };

        StringBuilder alarmStateInfo = new StringBuilder();

        for (int i = 0; i < alarmStr.length(); i++) {
            char bit = alarmStr.charAt(alarmStr.length() - 1 - i);
            if (bit == '1') {
                if (i < alarmDescriptions.length && alarmDescriptions[i] != null) {
                    if (alarmStateInfo.length() == 0) {
                        alarmStateInfo.append(alarmDescriptions[i]);
                    } else {
                        alarmStateInfo.append("/").append(alarmDescriptions[i]);
                    }
                }
            }
        }
        gpsReal.setAlarmStateInfo(alarmStateInfo.toString().trim());
    }

    @Override
    @Transactional
    public void handleHistoryAndAreaMsg(JSONObject json) {
//        log.info("处理位置信息GPS区域数据:{}", JSON.toJSONString(json));
        if(json.getDouble("lng")==null){
            return;
        }
        if (!CoordinateValidator.isValidCoordinates(json.getDouble("lat"), json.getDouble("lng"))) {
            return;
        }
        if ((roundToPrecision(json.getDouble("lng"),4) + "_" + roundToPrecision(json.getDouble("lat"),4)).equals("0.0_0.0")){
            return;
        }
        // 根据消息内容，从缓存中获取车辆配置ID
        String tid = json.getString("tid").substring(1);
        JSONObject cacheJson = redisCache.getCacheMapValue("carConfig", tid);
        if (cacheJson != null) {
            int configId = cacheJson.getIntValue("config_id");
            // GPS实时信息
            GpsDistrict gpsDistrict;
            GpsData gpsData = new GpsData();
            try {
                gpsData.setConfigId(configId);
                gpsData.setTerminalCode(tid);
                handleHistoryCoordinateConvert(json, gpsData);

                Position position = getTdtPosition(gpsData.getLng().doubleValue(), gpsData.getLat().doubleValue());
                handleHistaoryArea(gpsData, position);

                // 解析坐标位置，处理区域信息
                gpsDistrict = new GpsDistrict(configId,position);

//                System.out.println("GPS 区域解析结果: "+gpsDistrict.toString());

                // 批量保存区域信息（mysql）
                Constants.GPS_DISTRICT_QUEUE.add(gpsDistrict);

                if (Constants.GPS_DISTRICT_QUEUE.size() >= 500) {
                    List<GpsDistrict> gpsDistrictList = new ArrayList<>();
                    Constants.GPS_DISTRICT_QUEUE.drainTo(gpsDistrictList);
                    // 批量插入数据库
                    if (!gpsDistrictList.isEmpty()) {
                        // 批量插入数据库
                        dataMapper.saveDistrictAll(gpsDistrictList);
                    }
                    gpsDistrictList.clear();
                }

                // 批量保存历史GPS数据(mongodb)
                Constants.GPS_HISTORY_QUEUE.add(gpsData);

                if (Constants.GPS_HISTORY_QUEUE.size() >= 1000) {
                    List<GpsData> gpsDataList = new ArrayList<>();
                    Constants.GPS_HISTORY_QUEUE.drainTo(gpsDataList);
                    // 批量插入数据库
                    gpsDataService.saveGpsDataList(gpsDataList);
                    gpsDataList.clear();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }else {
//            log.info("未找到车辆配置信息，保存到历史GPS数据");
            GpsData gpsData = new GpsData();
            gpsData.setConfigId(0);
            gpsData.setTerminalCode(tid);
            handleHistoryCoordinateConvert(json, gpsData);

            Position position = getTdtPosition(gpsData.getLng().doubleValue(), gpsData.getLat().doubleValue());
            handleHistaoryArea(gpsData, position);
            // 批量保存历史GPS数据(mongodb)
            Constants.GPS_HISTORY_UNCONFIG_QUEUE.add(gpsData);

            if (Constants.GPS_HISTORY_UNCONFIG_QUEUE.size() >= 1000) {
                List<GpsData> gpsDataList = new ArrayList<>();
                Constants.GPS_HISTORY_UNCONFIG_QUEUE.drainTo(gpsDataList);
                // 批量插入数据库
                gpsDataService.saveGpsDataList(gpsDataList);
                gpsDataList.clear();
            }
        }
    }

    // 解析天地图坐标位置,缓存起来设置过期时间，过期后保存到数据库；再存一个所有key的缓存，能找到就从数据库再次放到缓存中继续使用。
    private Position getTdtPosition(Double lng, Double lat) {
        String cacheKey = roundToPrecision(lng,4) + "_" + roundToPrecision(lat,4);
        JSONObject position = redisCache.getCacheObject("position:info:"+cacheKey);
        if (position == null) {
            // 在判断有无该key有则去数据库取出来并重新添加到缓存
            if (redisCache.hasKey("cacheKeys:"+cacheKey)){
                position = dataMapper.getPositionInfo(cacheKey);
                // 缓存解析结果，以便后续查询
                if (position!= null){
                    position = position.getJSONObject("position_json");
                    redisCache.setCacheObject("position:info:"+cacheKey, position, 10*60, TimeUnit.SECONDS);
                }else {
                    position = TDTGPSUtils.gpsDecompilation(lng, lat).getJSONObject("result");
                    // 缓存解析结果，以便后续查询
                    redisCache.setCacheObject("position:info:"+cacheKey, position, 10*60, TimeUnit.SECONDS);
                }
            }else {
                position = TDTGPSUtils.gpsDecompilation(lng, lat).getJSONObject("result");
                // 缓存解析结果，以便后续查询
                redisCache.setCacheObject("position:info:"+cacheKey, position, 10*60, TimeUnit.SECONDS);
            }
        }
        return new Position(cacheKey,position);
    }

    private static double roundToPrecision(double value, int accuracy) {
        double multiplier = Math.pow(10, accuracy);
        return Math.round(value * multiplier) / multiplier;
    }

    private static void handleHistoryCoordinateConvert(JSONObject json, GpsData gpsData) {
        Double lng = json.getDouble("lng");
        Double lat = json.getDouble("lat");
        // 火星转天地图
        CoordinateTransformUtil.Coordinate wgs84ToCgcs2000 = CoordinateTransformUtil.wgs84ToCgcs2000(lng, lat);
        // 火星转高德
        CoordinateTransformUtil.Coordinate wgs84ToGcj02 = CoordinateTransformUtil.wgs84ToGcj02(lng, lat);
        // 火星转百度
        CoordinateTransformUtil.Coordinate wgs84ToBd09 = CoordinateTransformUtil.wgs84ToBd09(lng, lat);
        gpsData.setLng(BigDecimal.valueOf(wgs84ToCgcs2000.getLongitude()).setScale(6, RoundingMode.HALF_UP));
        gpsData.setLat(BigDecimal.valueOf(wgs84ToCgcs2000.getLatitude()).setScale(6, RoundingMode.HALF_UP));
        gpsData.setGdLng(BigDecimal.valueOf(wgs84ToGcj02.getLongitude()).setScale(6, RoundingMode.HALF_UP));
        gpsData.setGdLat(BigDecimal.valueOf(wgs84ToGcj02.getLatitude()).setScale(6, RoundingMode.HALF_UP));
        gpsData.setBaiduLng(BigDecimal.valueOf(wgs84ToBd09.getLongitude()).setScale(6, RoundingMode.HALF_UP));
        gpsData.setBaiduLat(BigDecimal.valueOf(wgs84ToBd09.getLatitude()).setScale(6, RoundingMode.HALF_UP));
        gpsData.setHeight(json.getInteger("height"));
        gpsData.setSpeed(json.getDouble("speed"));
        gpsData.setDirection(json.getInteger("direction"));
        gpsData.setGpsTime(DateUtils.handleGpsTime("yyyyMMddHHmmss", json.getString("gpstime")).getTime());
        if (json.getDouble("A01") != null) {
            gpsData.setMileage(roundToPrecision(json.getDouble("A01") / 10, 1));
        }
        if (json.getDouble("A02") != null) {
            gpsData.setOil(roundToPrecision(json.getDouble("A02") / 10, 1));
        }
        gpsData.setCreateTime(new Date());
    }

    private static void handleHistaoryArea(GpsData gpsData, Position position) {
        gpsData.setCityCode(position.getCityCode());
        gpsData.setAdcode(position.getAdcode());
        gpsData.setProvince(position.getProvince());
        gpsData.setCity(position.getCity());
        gpsData.setDistrict(position.getDistrict());
        gpsData.setCurAddress(position.getCurAddress());
    }

    @Override
    @Transactional
    public void handleRepairRealMsg(JSONObject json) {
//        log.info("处理补报实时GPS数据:{}", JSON.toJSONString(json));
        if(json.getDouble("lng")==null){
            return;
        }
        // 验证经纬度合法性， 不合法则不处理
        if (!CoordinateValidator.isValidCoordinates(json.getDouble("lat"), json.getDouble("lng"))) {
            return;
        }
        if ((roundToPrecision(json.getDouble("lng"),4) + "_" + roundToPrecision(json.getDouble("lat"),4)).equals("0.0_0.0")){
            return;
        }
        // 先缓存到本地，每100条批量插入数据库一次
        // 根据消息内容，从缓存中获取车辆配置ID
        String tid = json.getString("tid").substring(1);
        JSONObject cacheJson = redisCache.getCacheMapValue("carConfig", tid);
        if (cacheJson != null) {
            int configId = cacheJson.getIntValue("config_id");

            // 判断补报的数据是否已经失效，5分钟内，且时间大于当前库中最新的一条数剧
            JSONObject newGpsReal = redisCache.getCacheMapValue("gpsRealList", configId + "");
            Date date = DateUtils.handleGpsTime("yyyyMMddHHmmss", json.getString("gpstime"));
            if (newGpsReal!=null){
                Date gpsTime = newGpsReal.getDate("gpsTime");
                if (date.getTime()>new Date().getTime()-5*60*1000 && date.getTime()>gpsTime.getTime()){
                    // GPS实时信息
                    GpsReal gpsReal = new GpsReal();
                    try {
                        gpsReal.setConfigId(configId);
                        // 处理GPS实时信息
                        gpsReal.setTerminalCode(tid);

                        // 处理坐标转换
                        handleCoordinateConvert(json, gpsReal);
                        gpsReal.setHeight(json.getInteger("height"));
                        gpsReal.setSpeed(json.getDouble("speed"));
                        gpsReal.setDirection(json.getInteger("direction"));
                        gpsReal.setGpsTime(date);
                        gpsReal.setCreateTime(new Date());

                        // 处理报警位
                        Integer alarm = json.getInteger("alarm");
                        gpsReal.setAbnormalState(alarm);

                        // 处理报警描述
                        handleAlarmStr(alarm, gpsReal);

                        Integer status = json.getInteger("status");
                        // 通过位运算处理状态位
                        gpsReal.setAccState(status & 0x01);
                        gpsReal.setLocation((status >> 1) & 0x01);
                        gpsReal.setWeft((status >> 2) & 0x01);
                        gpsReal.setWarp((status >> 3) & 0x01);
                        gpsReal.setWorkState((status >> 4) & 0x01);

                        // 处理附加信息
                        if (json.getDouble("A01") != null) {
                            gpsReal.setMileage(roundToPrecision(json.getDouble("A01") / 10, 1));
                        }
                        if (json.getDouble("A02") != null) {
                            gpsReal.setOil(roundToPrecision(json.getDouble("A02") / 10, 1));
                        }
                        gpsReal.setLastTime(new Date());

                        // 将实时GPS信息放到缓冲队列中，每100条批量插入数据库一次
                        Constants.REPAIR_GPS_QUEUE.add(gpsReal);

                        if (Constants.REPAIR_GPS_QUEUE.size() >= 79) {
                            List<GpsReal> gpsRealList = new ArrayList<>();
                            Constants.REPAIR_GPS_QUEUE.drainTo(gpsRealList);
                            // 批量插入数据库
                            if (!gpsRealList.isEmpty()) {
                                // 批量插入数据库
                                dataMapper.saveRealAll(gpsRealList);
                            }
                            gpsRealList.clear();
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    @Override
    @Transactional
    public void handleRepairAlarmMsg(JSONObject json) {
//        log.info("处理补报实时GPS报警数据:{}", JSON.toJSONString(json));
        if(json.getDouble("lng")==null){
            return;
        }
        if (!CoordinateValidator.isValidCoordinates(json.getDouble("lat"), json.getDouble("lng"))) {
            return;
        }
        if ((roundToPrecision(json.getDouble("lng"),4) + "_" + roundToPrecision(json.getDouble("lat"),4)).equals("0.0_0.0")){
            return;
        }
        // 先缓存到本地，每100条批量插入数据库一次
        // 根据消息内容，从缓存中获取车辆配置ID
        String tid = json.getString("tid").substring(1);
        JSONObject cacheJson = redisCache.getCacheMapValue("carConfig", tid);
        if (cacheJson != null) {
            int configId = cacheJson.getIntValue("config_id");
            JSONObject newGpsReal = redisCache.getCacheMapValue("gpsRealList", configId + "");
            Date date = DateUtils.handleGpsTime("yyyyMMddHHmmss", json.getString("gpstime"));
            if (newGpsReal!=null){
                Date gpsTime = newGpsReal.getDate("gpsTime");
                if (date.getTime()>new Date().getTime()-5*60*1000 && date.getTime()>gpsTime.getTime()){
                    // GPS实时信息
                    GpsReal gpsReal = new GpsReal();
                    try {
                        gpsReal.setConfigId(configId);
                        gpsReal.setTerminalCode(tid);
                        // 处理报警位
                        Integer alarm = json.getInteger("alarm");
                        gpsReal.setAbnormalState(alarm);

                        // 处理报警描述
                        handleAlarmStr(alarm, gpsReal);

                        Integer status = json.getInteger("status");
                        // 通过位运算处理状态位
                        gpsReal.setAccState(status & 0x01);
                        gpsReal.setLocation((status >> 1) & 0x01);
                        gpsReal.setWeft((status >> 2) & 0x01);
                        gpsReal.setWarp((status >> 3) & 0x01);
                        gpsReal.setWorkState((status >> 4) & 0x01);

                        // 处理附加信息
                        if (json.getDouble("A01") != null) {
                            gpsReal.setMileage(roundToPrecision(json.getDouble("A01") / 10, 1));
                        }
                        if (json.getDouble("A02") != null) {
                            gpsReal.setOil(roundToPrecision(json.getDouble("A02") / 10, 1));
                        }
                        gpsReal.setLastTime(new Date());

                        Constants.REPAIR_GPS_STATUS_QUEUE.add(gpsReal);

                        if (Constants.REPAIR_GPS_STATUS_QUEUE.size() >= 133) {
                            List<GpsReal> gpsRealList = new ArrayList<>();
                            Constants.REPAIR_GPS_STATUS_QUEUE.drainTo(gpsRealList);
                            // 批量插入数据库
                            if (!gpsRealList.isEmpty()) {
                                // 批量插入数据库
                                dataMapper.saveRealOtherAll(gpsRealList);
                            }
                            gpsRealList.clear();
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    @Override
    @Transactional
    public void handleRepairHistoryAndAreaMsg(JSONObject json) {
//        log.info("处理补报位置信息GPS历史数据:{}", JSON.toJSONString(json));
        if(json.getDouble("lng")==null){
            return;
        }
        if (!CoordinateValidator.isValidCoordinates(json.getDouble("lat"), json.getDouble("lng"))) {
            return;
        }
        if ((roundToPrecision(json.getDouble("lng"),4) + "_" + roundToPrecision(json.getDouble("lat"),4)).equals("0.0_0.0")){
            return;
        }
        // 根据消息内容，从缓存中获取车辆配置ID
        String tid = json.getString("tid").substring(1);
        JSONObject cacheJson = redisCache.getCacheMapValue("carConfig", tid);
        if (cacheJson != null) {
            int configId = cacheJson.getIntValue("config_id");
            // GPS实时信息
            GpsDistrict gpsDistrict;
            GpsData gpsData = new GpsData();
            try {
                gpsData.setConfigId(configId);
                gpsData.setTerminalCode(tid);
                handleHistoryCoordinateConvert(json, gpsData);

                Position position = getTdtPosition(gpsData.getLng().doubleValue(), gpsData.getLat().doubleValue());
                handleHistaoryArea(gpsData, position);


                JSONObject newGpsReal = redisCache.getCacheMapValue("gpsRealList", configId + "");
                Date date = DateUtils.handleGpsTime("yyyyMMddHHmmss", json.getString("gpstime"));
                if (newGpsReal!=null){
                    Date gpsTime = newGpsReal.getDate("gpsTime");
                    if (date.getTime()>new Date().getTime()-5*60*1000 && date.getTime()>gpsTime.getTime()){
                        // 解析坐标位置，处理区域信息
                        gpsDistrict = new GpsDistrict(configId,position);

//                        System.out.println("GPS 区域解析结果: "+gpsDistrict.toString());

                        // 批量保存区域信息（mysql）
                        Constants.REPAIR_GPS_DISTRICT_QUEUE.add(gpsDistrict);

                        if (Constants.REPAIR_GPS_DISTRICT_QUEUE.size() >= 500) {
                            List<GpsDistrict> gpsDistrictList = new ArrayList<>();
                            Constants.REPAIR_GPS_DISTRICT_QUEUE.drainTo(gpsDistrictList);
                            // 批量插入数据库
                            if (!gpsDistrictList.isEmpty()) {
                                // 批量插入数据库
                                dataMapper.saveDistrictAll(gpsDistrictList);
                            }
                            gpsDistrictList.clear();
                        }
                    }
                }

                // 批量保存历史GPS数据(mongodb)
                Constants.REPAIR_GPS_HISTORY_QUEUE.add(gpsData);

                if (Constants.REPAIR_GPS_HISTORY_QUEUE.size() >= 500) {
                    List<GpsData> gpsDataList = new ArrayList<>();
                    Constants.REPAIR_GPS_HISTORY_QUEUE.drainTo(gpsDataList);
                    // 批量插入数据库
                    gpsDataService.saveGpsDataList(gpsDataList);
                    gpsDataList.clear();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }else {
//            log.info("未找到车辆配置信息，保存到历史GPS数据");
            GpsData gpsData = new GpsData();
            gpsData.setConfigId(0);
            gpsData.setTerminalCode(tid);
            handleHistoryCoordinateConvert(json, gpsData);

            Position position = getTdtPosition(gpsData.getLng().doubleValue(), gpsData.getLat().doubleValue());
            handleHistaoryArea(gpsData, position);
            // 批量保存历史GPS数据(mongodb)
            Constants.REPAIR_GPS_HISTORY_UNCONFIG_QUEUE.add(gpsData);

            if (Constants.REPAIR_GPS_HISTORY_UNCONFIG_QUEUE.size() >= 500) {
                List<GpsData> gpsDataList = new ArrayList<>();
                Constants.REPAIR_GPS_HISTORY_UNCONFIG_QUEUE.drainTo(gpsDataList);
                // 批量插入数据库
                gpsDataService.saveGpsDataList(gpsDataList);
                gpsDataList.clear();
            }
        }
    }

    @PreDestroy
    public void destroy() {
        //执行销毁前的最后一次
        System.out.println("执行销毁前的最后一次");
        if (!Constants.GPS_QUEUE.isEmpty()) {
            List<GpsReal> gpsRealList = new ArrayList<>();
            Constants.GPS_QUEUE.drainTo(gpsRealList);
            // 批量插入数据库
            if (!gpsRealList.isEmpty()) {
                // 批量插入数据库
                dataMapper.saveRealAll(gpsRealList);
            }
            gpsRealList.clear();
        }

        if (!Constants.GPS_STATUS_QUEUE.isEmpty()) {
            List<GpsReal> gpsRealList = new ArrayList<>();
            Constants.GPS_STATUS_QUEUE.drainTo(gpsRealList);
            // 批量插入数据库
            if (!gpsRealList.isEmpty()) {
                // 批量插入数据库
                dataMapper.saveRealOtherAll(gpsRealList);
            }
            gpsRealList.clear();
        }

        if (!Constants.GPS_DISTRICT_QUEUE.isEmpty()) {
            List<GpsDistrict> gpsDistrictList = new ArrayList<>();
            Constants.GPS_DISTRICT_QUEUE.drainTo(gpsDistrictList);
            // 批量插入数据库
            if (!gpsDistrictList.isEmpty()) {
                // 批量插入数据库
                dataMapper.saveDistrictAll(gpsDistrictList);
            }
            gpsDistrictList.clear();
        }

        if (!Constants.GPS_HISTORY_QUEUE.isEmpty()) {
            List<GpsData> gpsDataList = new ArrayList<>();
            Constants.GPS_HISTORY_QUEUE.drainTo(gpsDataList);
            // 批量插入数据库
            gpsDataService.saveGpsDataList(gpsDataList);
            gpsDataList.clear();
        }

        if (!Constants.GPS_HISTORY_UNCONFIG_QUEUE.isEmpty()) {
            List<GpsData> gpsDataList = new ArrayList<>();
            Constants.GPS_HISTORY_UNCONFIG_QUEUE.drainTo(gpsDataList);
            // 批量插入数据库
            gpsDataService.saveGpsDataList(gpsDataList);
            gpsDataList.clear();
        }

        if (!Constants.REPAIR_GPS_QUEUE.isEmpty()) {
            List<GpsReal> gpsRealList = new ArrayList<>();
            Constants.REPAIR_GPS_QUEUE.drainTo(gpsRealList);
            // 批量插入数据库
            if (!gpsRealList.isEmpty()) {
                // 批量插入数据库
                dataMapper.saveRealAll(gpsRealList);
            }
            gpsRealList.clear();
        }

        if (!Constants.REPAIR_GPS_STATUS_QUEUE.isEmpty()) {
            List<GpsReal> gpsRealList = new ArrayList<>();
            Constants.REPAIR_GPS_STATUS_QUEUE.drainTo(gpsRealList);
            // 批量插入数据库
            if (!gpsRealList.isEmpty()) {
                // 批量插入数据库
                dataMapper.saveRealOtherAll(gpsRealList);
            }
            gpsRealList.clear();
        }

        if (!Constants.REPAIR_GPS_DISTRICT_QUEUE.isEmpty()) {
            List<GpsDistrict> gpsDistrictList = new ArrayList<>();
            Constants.REPAIR_GPS_DISTRICT_QUEUE.drainTo(gpsDistrictList);
            // 批量插入数据库
            if (!gpsDistrictList.isEmpty()) {
                // 批量插入数据库
                dataMapper.saveDistrictAll(gpsDistrictList);
            }
            gpsDistrictList.clear();
        }

        if (!Constants.REPAIR_GPS_HISTORY_QUEUE.isEmpty()) {
            List<GpsData> gpsDataList = new ArrayList<>();
            Constants.REPAIR_GPS_HISTORY_QUEUE.drainTo(gpsDataList);
            // 批量插入数据库
            gpsDataService.saveGpsDataList(gpsDataList);
            gpsDataList.clear();
        }

        if (!Constants.REPAIR_GPS_HISTORY_UNCONFIG_QUEUE.isEmpty()) {
            List<GpsData> gpsDataList = new ArrayList<>();
            Constants.REPAIR_GPS_HISTORY_UNCONFIG_QUEUE.drainTo(gpsDataList);
            // 批量插入数据库
            gpsDataService.saveGpsDataList(gpsDataList);
            gpsDataList.clear();
        }

        System.out.println("---------------------执行结束");

    }


}
